package register

import (
	"gitee.com/FogVDN-API/pear/api/model"
	//"gitee.com/FogVDN-API/pear/rpc/client/scheduler"
	"encoding/json"
	"errors"
	"fmt"

	"math/rand"
	"time"

	"flag"
	"github.com/sirupsen/logrus"
	"github.com/valyala/fasthttp"
	"log"
)

var (
	ResNodes = flag.Int("nodes", 6, "get webrtc nodes")
)

func MaxResNodes() int {
	return *ResNodes
}

// 用于测试 只返回mac地址不返回sdp
type GetMacHandler struct {
	client *Client
	//_schedulerClient *scheduler.SchedulerClient
	//_regionDecoder RegionDecoder
}

type browserGetMac struct {
	Action string `json:"action"`
	PeerId string `json:"peer_id"`
	Host   string `json:"host"`
	Uri    string `json:"uri"`
	Md5    string `json:"md5"`
	Nat  int64 `json:"nat"`
}


type MacNodeInfo struct {
	Action       string     `json:"action,omitempty"`
	Host       string     `json:"host"`
	Uri       string     `json:"uri"`
	Mac       []nodesMac `json:"nodes"`
	ErrorCode string     `json:"errorcode,omitempty"`
	Msg       string     `json:"msg,omitempty"`
}
type nodesMac struct {
	PeerId string `json:"peer_id"`
}

func (m *GetMacHandler) Handle(message []byte) {
	logrus.Debugf("[GetMacHandler.Handle] into ...")
	browserGet:= new(browserGetMac)
	if err := json.Unmarshal(message, &browserGet); err != nil {
		log.Printf("[GetMacHandler.Handle] json.Unmarshal %s", err.Error())
		// TODO 错误处理
		return
	}
	log.Printf("[GetMacHandler.Handle] browserGet: %v", browserGet)
	m.client.SetId(browserGet.PeerId)
	go func() {
		log.Printf("get mac")
		const baseUrl = "v1/customer/nodes/unhealth?client_ip=%s&host=%s&uri=%s"
		fastClient := &fasthttp.Client{
			//ReadTimeout: 5*time.Second,
		}
		req := fasthttp.AcquireRequest()
		req.Header.SetMethod("GET")
		req.SetRequestURI(fmt.Sprintf(baseUrl, m.client.RemoteAddr(), browserGet.Host, browserGet.Uri))
		log.Printf("[info]: base url%v", fmt.Sprintf(baseUrl, m.client.RemoteAddr(), browserGet.Host, browserGet.Uri))
		req.SetHost(m.client.server.scheduler)
		resp := fasthttp.AcquireResponse()
		if err := fastClient.DoTimeout(req, resp, 10*time.Second); err != nil {
			log.Printf("[error]:get mac get scheduler :%s ", err)
		}
		if resp.StatusCode() != fasthttp.StatusOK {
			log.Printf("[error]:get handler get node info err:%d", resp.StatusCode())
			return
		}
		scheduler := new(Scheduler)
		nodeStates := new(NodeStates)
		if len(resp.Body()) != 0 {
			log.Printf("[info]:get mac http get scheduler resp body:%v", string(resp.Body()))
			err := json.Unmarshal(resp.Body(), scheduler)
			if err != nil {
				log.Printf("[error]:get mac get handle unhealth node json unmarshal err:%v", err)
			}
			for _, s := range scheduler.Nodes {
				var nodeAddr NodeAddress
				nodeAddr.MacAddr = s.Mac
				nodeStates.nodeAddress = append(nodeStates.nodeAddress, &nodeAddr)
			}
			log.Printf("[info]:get mac http get scheduler request:%v", nodeStates.nodeAddress[0].MacAddr)

			if m.responseVideo(browserGet, nodeStates, m.client.RemoteAddr()) {
				return
			}
		}
		m.responseNoVideo(browserGet)
		//		TODO
	}()
}

func (m *GetMacHandler) responseVideo(request *browserGetMac, nodes *NodeStates, remoteIp string) bool {
	//isOk := false

	//less than RESPNODENUM return all nodes
	//if len(nodes) > MaxResNodes() {
	//	nodes.RegionFilter(remoteIp, m._regionDecoder, func(states NodeStates) bool {
	//		if m.nodeSchedule(request, states) {
	//			isOk = true
	//			return false
	//		}
	//		return true
	//	})
	//	if isOk {
	//		return true
	//	}
	//}

	// TODO 重复过滤
	return m.nodeSchedule(request, nodes)
}

func (m *GetMacHandler) nodeSchedule(request *browserGetMac, nodes *NodeStates) bool {

	result := BrowserGetResponse{}

	var NatFilterNodes []string
	//
	//nodesSize := len(nodes)
	//logrus.Debugf("[GetMacHandler.nodeSchedule] into len(%d)", nodesSize)
	//if nodesSize == 0 {
	//	return false
	//}
	nodeResp := MacNodeInfo{}

	nodeResp.ErrorCode = "2000"
	nodeResp.Msg = "mac has been send"
	nodeResp.Action = "nodes_mac"
	nodeResp.Host = request.Host
	nodeResp.Uri = request.Uri
	var count int

	//过滤网络类型
	/*for _, node := range nodes.nodeAddress {

		nodeInfo, NatFilteFlag, err := m.getNodeInfo(node.MacAddr, request.Host, request.Uri, request.Md5)
		if err != nil {
			logrus.Debugf(err.Error())
			continue
		}
		if !NatFilteFlag {
			count++
			nodeResp.Mac = append(nodeResp.Mac, nodesMac{PeerId: nodeInfo.PeerId})
			//result.Nodes = append(result.Nodes, nodeInfo)
		} else {
			NatFilterNodes = append(NatFilterNodes, node.MacAddr)
		}
	}*/
	peerIds, _ := m.get6NodeInfo()
	for _, peerId := range peerIds {
		count++
		nodeResp.Mac = append(nodeResp.Mac, nodesMac{PeerId: peerId})
	}
	//nodeSize := len(result.Nodes)
	if count < 1 {
		if len(result.Nodes) == 0 && len(NatFilterNodes) == 0 {
			return false
		}

		for index, mac := range NatFilterNodes {
			peerId := m.getNatFilterNodeInfo(mac, request.Host, request.Uri, request.Md5)
			if peerId != "" {
				nodeResp.Mac = append(nodeResp.Mac, nodesMac{PeerId: peerId})
			}
			//nodeInfo = BrowserGetNodeInfo{
			//	Host: Host,
			//	Uri:  Uri,
			//	Md5:  Md5,
			//}
			//result.Nodes = append(result.Nodes,)
			if count + index + 1 == 10 {
				break
			}
		}
		m.client.jsonResponse(nodeResp)
		return true

	} else {
		resp := m.getRandNode(&nodeResp)
		for _, node := range resp.Mac {
			nodeResp.Mac = append(nodeResp.Mac, nodesMac{PeerId: node.PeerId})
		}
		m.client.jsonResponse(nodeResp)
		return true
	}
	return false
}

func (m *GetMacHandler) getNodeInfo(macAddr, Host, Uri, Md5 string) (*BrowserGetNodeInfo, bool, error) {
	m.client.server.lock.Lock()
	peer, ok := m.client.server.clients[model.NewMac(macAddr).String()]
	m.client.server.lock.Unlock()
	if !ok || len(peer.nodeAnnounce.Sdps) < 1 {
		return nil, false, errors.New(
			fmt.Sprintf("[GetMacHandler.getNodeInfo] %s=> ok:%v || Sdps.len < 1 ", macAddr, ok))
	}

	if time.Now().Unix()-peer.nodeAnnounce.Time > peer.nodeAnnounce.Timeout {
		return nil, false,
			errors.New(fmt.Sprintf("[GetMacHandler.getNodeInfo] %s timeout", macAddr))
	}

	if peer.nodeAnnounce.Nat >= 4 {
		return nil, true, nil
	}

	nodeInfo := &BrowserGetNodeInfo{
		Host: Host,
		Uri:  Uri,
		Md5:  Md5,
	}
	nodeInfo.Nat = peer.nodeAnnounce.Nat
	nodeInfo.PeerId = peer.nodeAnnounce.PeerId

	return nodeInfo, false, nil
}

func (m *GetMacHandler) get6NodeInfo() (result []string, err error) {
	i := 0
	m.client.server.lock.Lock()
	for _, peer := range m.client.server.clients{
		if i >= 6 {
			break
		}
		/*if time.Now().Unix()-peer.nodeAnnounce.Time > peer.nodeAnnounce.Timeout {
			continue
		}

		if peer.nodeAnnounce.Nat >= 4 {
			continue
		}*/
		result = append(result, peer.nodeAnnounce.PeerId)
		i++
	}
	m.client.server.lock.Unlock()
	return result, nil
}

func (m *GetMacHandler) getNatFilterNodeInfo(macAddr, Host, Uri, Md5 string) string {
	m.client.server.lock.Lock()
	peer, ok := m.client.server.clients[model.NewMac(macAddr).String()]
	m.client.server.lock.Unlock()
	if ok {
		return peer.nodeAnnounce.PeerId
	}
	return ""
}

func (m *GetMacHandler) getRandNode(mac *MacNodeInfo) (response *MacNodeInfo) {

	nodesSize := len(mac.Mac)
	index := rand.Perm(nodesSize)
	for i := 0; i < nodesSize && len(response.Mac) < MaxResNodes(); i++ {
		response.Mac = append(response.Mac, mac.Mac[index[i]])
	}
	return response
}

func (m *GetMacHandler) responseNoVideo(request *browserGetMac) {
	result := MacNodeInfo{
		ErrorCode: "4004",
		Msg:       "No such file",
	}
	logrus.Infof("[GetMacHandler.responseNoVideo] no such file: %s %s", request.Host, request.Uri)
	m.client.jsonResponse(result)
}
